import treeUtils from "@/utils/treeUtils";
import tableColumnMapper from "@/components/start-boot/columnMappingConfig";
import securityTools from "@/store/securityTools";
import {createDownloadFile} from "@/utils/util";
import avueDataAdapter from "@/utils/avueDataAdapter";
import startSearchModel from "@/config/startSearchModel";

function createMixin(option = {}) {
    return {
        computed: {
            pageOption() {
                return option;
            },
            columns() {
                let temp = [];
                for (let i = 0; i < this.tableOption.column.length; i++) {
                    let column = this.tableOption.column[i];
                    if (!column.columnComponent) continue
                    temp.push(column);
                }
                return temp;
            },
            bindVal() {
                return {
                    ref: 'crud',
                    option: this.tableOption,
                    data: this.dataSource,
                    tableLoading: this.loading,
                    permission: this.getBtnPermission,
                    beforeOpen: this.dialogBeforeOpen,
                    beforeClose: this.dialogBeforeClose
                }
            },
            onEvent() {
                return {
                    'on-load': this.getList,
                    'row-save': this.rowSave,
                    'row-update': this.rowUpdate,
                    'row-del': this.rowDel,
                    'refresh-change': this.refreshChange,
                    'search-reset': this.searchChange,
                    'search-change': this.searchChange,
                    'selection-change': this.selectionChange,
                    'sort-change': this.sortChange
                }
            },
            rowKey() {
                return option.rowKey || 'id'
            }
        },
        data() {
            let temp = require(`@/option/${option.name + (option.optionSuffix || 'Option')}`).default(this);
            let columns = temp.column;
            let columnsMap = {};
            for (let i = 0; i < columns.length; i++) {
                let column = columns[i];
                if (column.search) {
                    columnsMap[column.prop] = column.searchModel ? column.searchModel : startSearchModel.EQ;
                }
                let columnType = column.component;
                if (!columnType) {
                    columnType = column.type;
                }

                if (!tableColumnMapper[columnType]) continue
                if (column.slot) continue;
                column.slot = true
                column.columnComponent = tableColumnMapper[columnType];
            }
            let permissionBtnTemp = temp.permissionBtn;
            if (!permissionBtnTemp) permissionBtnTemp = {};
            if (option.permissionBtn) {
                permissionBtnTemp = Object.assign(permissionBtnTemp, option.permissionBtn)
            }
            let apiPath = option.name + (option.apiSuffix || "Api");
            return {
                permissionBtn: permissionBtnTemp,
                tableOption: temp,
                dataSource: [],
                startForm: {},
                searchParams: {},
                api: require(`@/api/${apiPath}`),
                loading: false,
                page: {
                    currentPage: 1,
                    pageSize: 10,
                },
                tempOption: null,
                columnsMap,
                selectList: [],
            }
        },
        beforeCreate() {
        },
        created() {
        },
        methods: {
            getList() {
                this.loading = true;
                this.dataSource = [];
                let pageParams = {}
                pageParams[option.current || 'current'] = this.page.currentPage
                pageParams[option.size || 'size'] = this.page.pageSize;
                let searchParams = this.getSearchParams();
                if (this.getListBefore) {
                    let tempBefore = this.getListBefore(searchParams)
                    searchParams = tempBefore ? tempBefore : searchParams;
                }
                const requestData = Object.assign(pageParams, this.searchParams, searchParams)
                this.api[option.list || 'list'](requestData).then(res => {
                    let data = res.data.data;
                    if (this.getListAfter) this.getListAfter(data);
                    let tempDataList;
                    if (data instanceof Array) {
                        tempDataList = data;
                    } else {
                        tempDataList = data[option.data || 'records'];
                        this.page.total = data[option.total || 'total'];
                    }

                    avueDataAdapter.transformDataList(this.tableOption.column, tempDataList)
                    if (option.isTreeData)
                        tempDataList = treeUtils.listToTree(tempDataList)
                    this.dataSource = tempDataList;
                }).finally(() => this.loading = false)

            },
            restLoadList() {
                this.page.currentPage = 1;
                this.getList();
            },
            getSearchParams() {
                let searchParams = {};
                for (const columnKey in this.searchParams) {
                    if (!this.searchParams[columnKey] || this.searchParams[columnKey].length < 1) continue
                    let searchModel = this.columnsMap[columnKey];
                    if (!searchModel) continue;
                    switch (searchModel) {
                        case startSearchModel.BETWEEN:
                        case startSearchModel.NOT_BETWEEN:
                        case startSearchModel.IN:
                        case startSearchModel.NOT_IN:
                            searchParams["start_search_" + columnKey] = this.columnsMap[columnKey] + this.searchParams[columnKey].join(",")
                            continue;
                    }
                    searchParams["start_search_" + columnKey] = this.columnsMap[columnKey] + this.searchParams[columnKey]
                }
                return searchParams
            },
            rowSave(row, done, loading) {
                delete this.startForm.params;
                if (this.rowSaveBefore) {
                    this.rowSaveBefore(row);
                }
                avueDataAdapter.transformDataSave(this.tableOption.column, row)
                this.api[option.add || 'add'](row).then((data) => {
                    this.getList();
                    this.$message.success('新增成功')
                }).finally(() => {
                    if (this.rowSaveAfter) this.rowSaveAfter(row, index);
                    done()
                })

            },
            rowUpdate(row, index, done, loading) {
                delete this.startForm.params;
                if (this.rowUpdateBefore) this.rowUpdateBefore(row, index);
                avueDataAdapter.transformDataSave(this.tableOption.column, row)
                let update = this.api[option.update || 'updateById'];
                update(row[this.rowKey], row, index).then((data) => {
                    this.getList();
                    this.$message.success('更新成功')
                }).finally(() => {
                    done()
                    if (this.rowUpdateAfter) this.rowUpdateAfter(row, index);
                })

            },
            rowDel(row, index) {
                this.$confirm(`此操作将永久删除序号为【${index + 1}】的数据！ 是否继续?`, '系统提示', {
                    confirmButtonText: '是',
                    cancelButtonText: '否',
                    type: 'warning'
                }).then(() => {
                    if (this.rowDelBefore) this.rowDelBefore(row, index);
                    return this.api[option.del || 'deleteById'](row[this.rowKey], row)
                }).then(res => {
                    this.getList();
                    this.$message.success('删除成功')
                    if (this.rowDelAfter) this.rowDelAfter(row, index);
                })

            },
            searchChange(params, done) {
                if (done) done();
                this.searchParams = params;
                this.page.currentPage = 1;
                this.getList();
            },
            refreshChange() {
                this.getList();
            },
            getBtnPermission(btnKey, row, index, defaultValue = true) {
                if (!this.permissionBtn[btnKey]) return defaultValue;
                let code = this.permissionBtn[btnKey];
                let v;
                if (option.permissionBtnHandler && option.permissionBtnHandler[btnKey]) {
                    v = option.permissionBtnHandler[btnKey](this, row, defaultValue);
                } else {
                    v = securityTools.actions.hasPermission(code, defaultValue)
                }
                return v;
            },
            downloadTemplate(fileName) {
                let downloadTemplate = this.api[option.downloadTemplate || 'downloadTemplate'];
                if (!downloadTemplate) {
                    this.$message.info("未定义模板下载接口")
                    return
                }
                downloadTemplate().then(res => createDownloadFile(res, fileName))
            },
            downloadExportExcel(fileName) {
                let exportExcel = this.api[option.exportExcel || 'exportExcel'];
                if (!exportExcel) {
                    this.$message.info("未定义数据导出接口")
                    return;
                }
                let searchParams = this.getSearchParams();
                exportExcel(searchParams).then(res => createDownloadFile(res, fileName));
            },
            handlerImportExcel() {
                let importExcelApi = this.api[option.importExcel || 'importExcel'];
                if (!importExcelApi) {
                    this.$message.info("未定义数据导入接口")
                    return
                }
                this.$refs.importExcel.show();
            },
            selectionChange(list) {
                this.selectList = list;
            },
            batchRowDel() {
                if (this.selectList.length < 1) return;
                let ids = [];
                for (let i = 0; i < this.selectList.length; i++) {
                    ids.push(this.selectList[i][this.rowKey])
                }
                this.$confirm(`此操作将永久删除id为【${ids.join('\n')}】的数据！ 是否继续?`, '系统提示', {
                    confirmButtonText: '是',
                    cancelButtonText: '否',
                    type: 'warning'
                }).then(() => {
                    if (this.batchRowDelBefore) this.batchRowDelBefore(ids, selectList);
                    return this.api[option.dels || 'deleteByIds'](ids)
                }).then(() => {
                    this.getList();
                    this.$message.success('删除成功')
                    if (this.batchRowDelAfter) this.batchRowDelAfter(row, index);
                })

            },
            sortChange(val) {
                console.log("排序变化", val)
            },
            dialogBeforeOpen(done, type) {
                let handler = null;
                if (type === 'add' && this.beforeOpenAddDialog) {
                    handler = this.beforeOpenAddDialog(this.startForm, done)
                } else if (type === 'edit' && this.beforeOpenEditDialog) {
                    handler= this.beforeOpenEditDialog(this.startForm, done)
                } else if (type === "view" && this.beforeOpenViewDialog) {
                    handler = this.beforeOpenViewDialog(this.startForm, done)
                }
                if (!handler) {
                    done()
                }
            },
            dialogBeforeClose(done, type) {
                let handler = null;
                if (type === 'add' && this.beforeCloseAddDialog) {
                    handler = this.beforeCloseAddDialog(this.startForm, done)
                } else if (type === 'edit' && this.beforeCloseEditDialog) {
                    handler = this.beforeCloseEditDialog(this.startForm, done)
                } else if (type === "view" && this.beforeCloseViewDialog) {
                    handler = this.beforeCloseViewDialog(this.startForm, done)
                }
                if (!handler) {
                    done()
                }
            },
        },
    }

}

export function createStartMixin(option = {}) {
    return createMixin(option);
}

export default (app, option = {}) => {
    let mixin = createStartMixin(option);
    app.mixins = app.mixins || [];
    app.mixins.push(mixin);
    option.that = app;
    return app;
}
